Skip to content

Recognize the Japanese maiden marker 旧姓 (#309) - #330

Merged
derek73 merged 1 commit into
masterfrom
feat/kyusei-maiden-marker
Aug 3, 2026
Merged

Recognize the Japanese maiden marker 旧姓 (#309)#330
derek73 merged 1 commit into
masterfrom
feat/kyusei-maiden-marker

Conversation

@derek73

@derek73 derek73 commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Reopens the useful half of #309, which was closed in favour of #329.

parse("山田花子 旧姓 佐藤")    # family 山田花子, maiden 佐藤
parse("山田 花子 旧姓 佐藤")   # given 花子, family 山田, maiden 佐藤

1.4.0 left the marker in the name — first 山田花子 / middle 旧姓 / last 佐藤.

Why the default vocabulary and not locales.JA

旧姓 sits beside the Cyrillic урожд. and German geb. entries, on the rule that admitted those:

Native-script entries cannot collide with Latin-script names, which is what makes them safe to enable by default.

Verified: matching is whole-token, _normalize("旧姓") is 旧姓, and neither character appears in any shipped surname, title, suffix, conjunction, particle or bound-given vocabulary.

The pack exists for what needs the my-data-is-Japanese declaration — segmentation, where a pure-Han string cannot say which language wrote it. A Han-script marker needs no such declaration, because it can only ever match Han text. Patching maiden_delimiters in the pack would also have been wrong for an independent reason: () is already a nickname delimiter and _extract resolves the collision by exclusion, so it would trade fullwidth-paren nicknames for maiden names wholesale (measured — 山田 太郎(マイケル・ジャクソン) moves from nickname to maiden).

Scope, stated in three places rather than left to discovery

This reaches the spaced form only. Japanese more often brackets the marker, and 山田(旧姓:佐藤) under Policy(maiden_delimiters=...) still returns maiden "旧姓:佐藤" with the marker and its colon attached — _extract claims delimited content whole, before classify has tagged anything inside it, so _group's marker-consuming rule never sees it.

That is not a Japanese limitation. Jane Smith (née Jones) keeps its marker the same way, where the bare Jane Smith née Jones drops it. Closing that asymmetry is #329.

The limit is recorded in the vocabulary file's docstring, both case-row notes, and the release-log entry.

The differential rule is its own, deliberately

fix(#274) maiden markers consumed declares fields = ["maiden", "middle", "last"]. The Japanese diff touches four:

first:  '山田花子' -> ''
middle: '旧姓'    -> ''
last:   '佐藤'    -> '山田花子'
maiden: ''        -> '佐藤'

first moves because the name left after the marker is consumed is wholly Han, so it reads family-first (#271) — the maiden fix compounding with the order flip, the same pattern already named by cjk-comma-compound and cjk-honorific-suffix.

Adding first to #274's field list would have made that rule broader than its prose and let it absorb diffs unrelated to markers, which is exactly the hazard filed as #328. The new rule's name_regex is the marker itself, so it can claim nothing else.

Verification

  • Suite 2942, mypy / ruff / Sphinx -W clean
  • Differential 750 names, unexplained: 0; both new rows claimed by the new narrow rule
  • Two case rows, classified fix(#309) against measured 1.4.0 values
  • corpus_cjk.jsonl regenerated from the case table

🤖 Generated with Claude Code

"山田花子 旧姓 佐藤" now gives family 山田花子 and maiden 佐藤, where
1.4.0 left the marker in the name (middle 旧姓).

Default vocabulary, not locales.JA, on the rule that admitted урожд.
and geb.: a native-script marker cannot collide with a Latin-script
name and matching is whole-token, so it is safe as a default. The pack
is for what needs the my-data-is-Japanese declaration -- segmentation,
where a pure-Han string cannot say which language wrote it -- and this
needs none, since it can only ever match Han text.

It reaches the SPACED form only, which the row notes and the release
log both say out loud rather than leaving to discovery: Japanese more
often brackets the marker, and "山田(旧姓:佐藤)" under
maiden_delimiters still returns maiden "旧姓:佐藤", marker and colon
attached, because extract claims delimited content whole before
classify has tagged anything inside it. Not a Japanese limitation --
"Jane Smith (née Jones)" keeps its marker the same way -- and closing
it is #329.

The differential rule is its own rather than a widening of fix(#274):
a Latin marker moves maiden/middle/last, while a Han one also flips
`first`, since the name left after the marker is consumed is wholly
Han and reads family-first. Adding `first` to #274's fields would make
that rule broader than its prose and let it absorb diffs unrelated to
markers (#328). This regex is the marker itself, so it can claim
nothing else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@derek73 derek73 self-assigned this Aug 3, 2026
@derek73 derek73 added this to the v2.1 milestone Aug 3, 2026
@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.47%. Comparing base (7f4074d) to head (0fa17c8).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #330   +/-   ##
=======================================
  Coverage   98.47%   98.47%           
=======================================
  Files          41       41           
  Lines        2823     2823           
=======================================
  Hits         2780     2780           
  Misses         43       43           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@derek73
derek73 merged commit 3af1e37 into master Aug 3, 2026
11 checks passed
@derek73
derek73 deleted the feat/kyusei-maiden-marker branch August 3, 2026 04:03
derek73 added a commit that referenced this pull request Aug 3, 2026
…ons need a sweep

Two failures from #329/#330, one bullet.

A sentence about which stage does what has a one-command answer here --
the ownership map is written down and pinned, and parse(s).tokens
prints roles and tags. "Extract claims delimited content before
classify has tagged anything inside it" was written without running
that command, and it is wrong twice over: classify does tag the marker,
and the colon form fails for an unrelated reason (one token, nothing to
tag). One plausible sentence covering two different mechanisms.

And it shipped in three places, because the correction landed on the
issue where it was found and nowhere else. This file's own line 10
already says a staleness sweep must READ rather than grep; the missing
half is that the sweep is also owed when YOUR OWN claim changes, not
only when the code does.

Placed beside the Typing/docs bullet, which records the same lesson for
a different claim shape ("written twice and falsified twice, at sites
the author had not audited") -- two entries in what is becoming a
pattern, kept findable separately because the tells differ.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant